/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#pragma once
#include "zen_al_platform.h"
#include "zen_point.h"

namespace Zen {

	enum class eALPlayState {
		Inital = AL_INITIAL,
		Playing = AL_PLAYING,
		Paused = AL_PAUSED,
		Stoped = AL_STOPPED,
	};

	class ALSource
	{
	protected:
		ALuint  mSource;
		ALSource(ALSource const&) = delete;
		void operator = (ALSource const&) = delete;
	public:
		ALSource();

		~ALSource();

		void Generate();

		void Release();

		void SetPitch(float value) const;

		void SetGain(float value) const;

		void SetPosition(Point3) const;

		void SetVelocity(Point3) const;

		void SetLooping(bool loop) const;

		float GetPitch() const;

		float GetGain() const;

		Point3 GetPosition() const;

		Point3 GetVelocity() const;

		bool IsLooping() const;

		void BindSound(ALuint bufferID) const;

		ALuint GetALSourceID() const;

		eALPlayState GetPlayState() const;
	};
}


namespace Zen {
	inline ALSource::ALSource()
	{
		mSource = 0;
	}
	inline ALSource::~ALSource()
	{
		Release();
	}
	inline void ALSource::Generate()
	{
		if (mSource != 0) return;
		alGenSources(1, &mSource);
		__zen_must_else(mSource != 0, "failed to Generate openal source");
	}
	inline void ALSource::Release()
	{
		if (mSource != 0)
		{
			alDeleteSources(1, &mSource);
			mSource = 0;
		}
	}
	inline void ALSource::SetPitch(float value) const
	{
		alSourcef(mSource, AL_PITCH, value);
	}
	inline void ALSource::SetGain(float value) const
	{
		alSourcef(mSource, AL_GAIN, value);
	}
	inline void ALSource::SetPosition(Point3 pos) const
	{
		alSource3f(mSource, AL_POSITION, pos.x, pos.y, pos.z);
	}
	inline void ALSource::SetVelocity(Point3 motion) const
	{
		alSource3f(mSource, AL_VELOCITY, motion.x, motion.y, motion.z);
	}
	inline void ALSource::SetLooping(bool loop) const
	{
		alSourcei(mSource, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
	}
	inline float ALSource::GetPitch() const
	{
		ALfloat value = 0.f;
		alGetSourcef(mSource, AL_PITCH, &value);
		return value;
	}
	inline float ALSource::GetGain() const
	{
		ALfloat value = 0.f;
		alGetSourcef(mSource, AL_GAIN, &value);
		return value;
	}
	inline Point3 ALSource::GetPosition() const
	{
		ALfloat x = 0.f, y = 0.f, z = 0.f;
		alGetSource3f(mSource, AL_POSITION, &x, &y, &z);
		return Point3{ x, y, z };
	}
	inline Point3 ALSource::GetVelocity() const
	{
		ALfloat x = 0.f, y = 0.f, z = 0.f;
		alGetSource3f(mSource, AL_VELOCITY, &x, &y, &z);
		return Point3{ x, y, z };
	}
	inline bool ALSource::IsLooping() const
	{
		ALint value;
		alGetSourcei(mSource, AL_LOOPING, &value);
		return value == AL_TRUE;
	}
	inline void ALSource::BindSound(ALuint buffer) const
	{
		alSourcei(mSource, AL_BUFFER, (ALint)buffer);
	}
	inline ALuint ALSource::GetALSourceID() const
	{
		return mSource;
	}
	inline eALPlayState ALSource::GetPlayState() const
	{
		ALint state;
		alGetSourcei(mSource, AL_SOURCE_STATE, &state);
		return (eALPlayState)state;
	}
}
